package com.sixi.GeoTransfer;

import java.awt.Point;
import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import com.sixi.GeoTransfer.model.Area;
import com.sixi.GeoTransfer.model.AreaModel;
import com.sixi.GeoTransfer.model.City;

import static com.sixi.GeoTransfer.Constants.*;
/**
 * @author Vincent
 *
 */
public class RatInCatUtils {
	
	@SuppressWarnings("rawtypes")
	public static List loadCityInfo(String filePath, String province) {
		if(filePath == null || filePath.equals("")) {
			filePath = SOURCE_FILE_PATH;
		}
		
		File f = new File(filePath);
		BufferedReader br = null;
		List<City> cityList = new ArrayList<City>();
		System.out.println("读取" + province + "省城市边界经纬度信息");
		try {
			br = new BufferedReader(new FileReader(f));
			String temp;
			while ((temp = br.readLine()) != null) {
				String[] districtInfoArray = temp.split("\\t");
				if(districtInfoArray.length == DISTRICT_INFO_COL_NUM) {
					City city = new City();
					city.setAdCode(districtInfoArray[1]);
					city.setCityCode(districtInfoArray[2]);
					String[] ctPoint = districtInfoArray[3].split(",");
					if(2 == ctPoint.length) {
						Point2D.Double ctp = new Point2D.Double(Double.parseDouble(ctPoint[0]),Double.parseDouble(ctPoint[1]));
						city.setCentre(ctp);
					}
					city.setCountry(districtInfoArray[5]);
					city.setProvince(districtInfoArray[6]);
					city.setName(districtInfoArray[7]);
					List<Point2D.Double> polyLine = new ArrayList<Point2D.Double>();
					String[] points = districtInfoArray[8].split(";");
					if(points.length > 2) {//大于2才能组成多边形
						for(String pt : points) {
							String[] ptSpli = pt.split(",");
							if(ptSpli.length == 2) {
								Point.Double vertex = new Point.Double(Double.parseDouble(ptSpli[0]), Double.parseDouble(ptSpli[1])) ;
								polyLine.add(vertex);
							}
						}
					}
					city.setPolyLine(polyLine);
					
					cityList.add(city);
				}
				
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return cityList;
	}
	
	public static List loadAreaInfo(String filePath, String province) {
		if(filePath == null || filePath.equals("")) {
			filePath = SOURCE_FILE_PATH;
		}
		
		File f = new File(filePath);
		BufferedReader br = null;
		List<Area> areaList = new ArrayList<Area>();
		System.out.println("读取" + province + "省市县边界经纬度信息");
		try {
			br = new BufferedReader(new FileReader(f));
			String temp;
			while ((temp = br.readLine()) != null) {
				String[] districtInfoArray = temp.split("\\t");
				if(districtInfoArray.length == AREA_INFO_COL_NUM) {
					Area area = new Area();
					area.setAdCode(districtInfoArray[1]);
					area.setCityCode(districtInfoArray[2]);
					String[] ctPoint = districtInfoArray[3].split(",");
					if(2 == ctPoint.length) {
						Point2D.Double ctp = new Point2D.Double(Double.parseDouble(ctPoint[0]),Double.parseDouble(ctPoint[1]));
						area.setCentre(ctp);
					}
					area.setAreaLevel(districtInfoArray[4]);
					area.setCountry(districtInfoArray[5]);
					area.setProvince(districtInfoArray[6]);
					area.setCity(districtInfoArray[7]);
					area.setName(districtInfoArray[8]);
					List<Point2D.Double> polyLine = new ArrayList<Point2D.Double>();
					String[] points = districtInfoArray[9].split(";");
					if(points.length > 2) {//大于2才能组成多边形
						for(String pt : points) {
							String[] ptSpli = pt.split(",");
							if(ptSpli.length == 2) {
								Point.Double vertex = new Point.Double(Double.parseDouble(ptSpli[0]), Double.parseDouble(ptSpli[1])) ;
								polyLine.add(vertex);
							}
						}
					}
					area.setPolyLine(polyLine);
					
					areaList.add(area);
				}
				
			}
			
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return areaList;
	}
	
	public static String ratInCatName(Point2D.Double rat,List <? extends AreaModel> cats) {
		String theCat = "Rat not in any Cat";
		//通过远近排序
		List<AreaModel> sortedCats = distanceSort(rat, cats);
		boolean inCat = false;
		int i = 0;
		
		while(!inCat && i < sortedCats.size()) {
			inCat = isRatInCat(rat, sortedCats.get(i).getPolyLine());
			theCat = sortedCats.get(i).getName();
			i++;
		}
		if(!inCat) {
			theCat = "未包含";
			System.out.print(sortedCats.get(1).getName() + " ");
		}
		return theCat;
	}
	
	public static AreaModel ratInCatAreaModel(Point2D.Double rat,List <? extends AreaModel> cats) {
		AreaModel returnArea = null;
		//通过远近排序
		List<AreaModel> sortedCats = distanceSort(rat, cats);
		boolean inCat = false;
		int i = 0;
		
		while(!inCat && i < sortedCats.size()) {
			inCat = isRatInCat(rat, sortedCats.get(i).getPolyLine());
			if(inCat) {//如果包含在结果中
				returnArea = sortedCats.get(i);
				return returnArea;
			}
			i++;
		}
		return returnArea;
	}
	
	
	
	/**
	 * To judge whether rat in the cat
	 * 
	 * @param rat
	 * @param cat 
	 * @return
	 */
	public static boolean isRatInCat(Point2D.Double rat, List<Point2D.Double> cat) {
		int N = cat.size();//点数
		int intersectCount = 0;// 交叉次数
//		double precision = 1e-10;//计算射线交点时的容差，精确度
		Point2D.Double p1,p2;//线段的两个端点
		Point2D.Double p = rat;//等待被判定的点
		
		p1 = cat.get(0);//将list的第一个点赋值给p1
		for(int i =1; i <=N ; i++) {//循环到最后一位确保余数最后=0，可以让第一个端点当做末端点
			if(p.equals(p1)) {//如果p点就是p1点，情况2
				return true;//p点在端点上
			}
			
			p2 = cat.get(i % N);//取余数确保最后一个末端点是首个点
			if(p.y < Math.min(p1.y, p2.y) || p.y > Math.max(p1.y, p2.y)) {//如果线段的端点都在射线的上方和下方,说明和线段无交点进行下一循环
				p1 = p2;
				continue;
			}
			
			if(p.y > Math.min(p1.y, p2.y) && p.y < Math.max(p1.y, p2.y)) {//p点的y值在p1和p2的y值区间内
				if(p.x <= Math.max(p1.x, p2.x)) {//p点位于线段左侧，否则不相交
					if(p1.x == p2.x){//p1p2线段是垂直的
						if(p1.x == p.x) {//p点在线段上(情况1a)
							return true;
						}else {//p点未在线段上
							intersectCount++;//相交次数+1
						}
					}else {//p1p2线段不是垂直的
						double xcross = (p.y - p1.y) * (p2.x-p1.x)/(p2.y - p1.y) + p1.x; //p射线的交点的x值
						if(Math.abs(p.x - xcross) < PRECISION) {//当做p点在线段上（情况1b）
							return true;
						}
						
						if(p.x < xcross) { //p点在交点（线段）左侧，否则不相交
							intersectCount++;//相交次数+1s
						}
					}
				}
			}else {//如果射线穿过线段的某一点或两点
				if(p1.y == p2.y) { //p1p2线段是条水平线
					if(p1.y == p.y && p.x >= Math.min(p1.x, p2.x)) {//p点在线段上或者在某个端点上（情况1c）
						return true;
					}//如果是其他情况则没穿过这条水平线段
				}else {//如果线段不是水平线,射线穿过某个端点（情况3）
					if(p.y == p2.y && p.x < p2.x) {//p点在p2点左边，p射线与p1p2相较于p2点
						Point2D.Double p3 = cat.get((i +1) % N);//引入下一点p3
						if(p.y > Math.min(p1.y, p3.y) && p.y <= Math.max(p1.y, p3.y)) {//假定p2点与p射线之上,py落于p1y和p3y之间
							intersectCount++;//相交次数+1s
						}
						if(p.y > Math.max(p1.y, p3.y)) {
							intersectCount+=2;//相交次数+2
						}
						//py <= Math.min(p1.y, p3.y) <假设交点p2在p点之上，则表示不相交
					}
				}
			}
			p1 = p2;//将p2点赋值给p1点，开始下一次循环
			
		}
		
		if (intersectCount % 2 == 0) {// 偶数在多边形外
			return false;
		} else { // 奇数在多边形内
			return true;
		}
	}
	
	

	/**
	 * 插入排序
	 * 
	 * 1. 从第一个元素开始，该元素可以认为已经被排序 
	 * 2. 取出下一个元素，在已经排序的元素序列中从后向前扫描
	 * 3. 如果该元素（已排序）大于新元素，将该元素移到下一位置
	 * 4. 重复步骤3，直到找到已排序的元素小于或者等于新元素的位置
	 * 5. 将新元素插入到该位置中
	 * 6. 重复步骤2
	 * 
	 * @param numbers 待排序数组
	 */
	public static void insertSort(double[] numbers) {
		int size = numbers.length;
		double temp = 0;
		int j = 0;

		for (int i = 0; i < size; i++) {
			temp = numbers[i];
			// 假如temp比前面的值小，则将前面的值后移
			for (j = i; j > 0 && temp < numbers[j - 1]; j--) {
				numbers[j] = numbers[j - 1];//后移
			}
			numbers[j] = temp;
		}
	}
	
	
	
	/**
	 * sorting by distance。reduce comput time
	 * 
	 * @param rat
	 * @param areas
	 * @return
	 */
	public static List<AreaModel> distanceSort(Point2D.Double rat, List<? extends AreaModel> areas) {
		int size = areas.size();
		double temp = 0;
		
		List<AreaModel> sortedList = new ArrayList<AreaModel>();
		Map<Double, AreaModel> map = new HashMap<Double, AreaModel>();
		
		for (int i = 0; i < size; i++) {
			AreaModel am = areas.get(i);
			temp = rat.distance(am.getCentre());
			map.put(temp, am);
		}
		
		 SortedMap<Double,AreaModel> sort=new TreeMap<Double,AreaModel>(map);
//		 sort.keySet();
		 Set<Entry<Double, AreaModel>>  sortedSet = sort.entrySet();
		 
		 Iterator<Entry<Double,AreaModel>> it=sortedSet.iterator();  
		 
		 while(it.hasNext()) {
			 Entry<Double,AreaModel> entry=it.next();
			 sortedList.add(entry.getValue());
//	         System.out.println("排序之后:"+entry.getKey()+" 值"+entry.getValue());    
		 }
		 
		 return sortedList;
		 
	}
}
